/*
Online Java - IDE, Code Editor, Compiler
Online Java is a quick and easy tool that helps you to build, compile, test your programs
online.
*/

//This is version
//https://www.amitamlani.com/02112024/7/2/Main.java
//It does not have the method generate3x3grid
//It does not fall into StackOverflowError so I have preserved this code.
//I am simply adding content from
//https://www.amitamlani.com/02112024/9/Permutation%20-%20with%20violation%20details.java
//and will follow advise followed by chatGPT to ensure full execution


import java.math.*;
import java.util.*;
import java.util.stream.*;

interface Fillable   //KEEP
{
    public void fill3x3();
    public void fill9x9(Map<Integer, int[][]> mp);
    public boolean checkUniqueRows(int [][] temp, int rowIndex);
    public boolean checkUniqueColumns(int[][] nineByNine, int colIndex);
    public boolean sudokuComplete(boolean a, boolean b);
    public void wipe9x9Board(int[][] formattedBoard, int[][] nineByNine);
    public void print9x9Board(String history, int numComplete9x9Boards);
    public int convertStringTo3x3(String permutations3x3, int getNumString);
    public void realTime9x9Fill(String history);
    public void display9x9();

}

class Sudoku implements Fillable
{
    int minimum=362880;
    int maximum=0;

    int randomNumber;
    StringJoiner summary;
    StringJoiner summary1;

    //Moved this across to BigInteger. It did not work previously since I was unable
    //to increment this by one
    int numAttempts;
    //BigInteger numAttempts=new BigInteger("0");

    //I introduced this to keep track of number completed suduko boards which pass validation
    //BigInteger numSuccessfulCompletedBoards = new BigInteger("0");
    int numSuccessfulCompletedBoards = 0;

    int numRetrieved3x3GridsIn9x9Grid;

    int numberPossibleBoards = 1000000;

    Set<String> permutationAllBoards = new HashSet();

    Map<Integer, int[][]> mp = new HashMap();

    int possibleNumbers[] = new int[]{1,2,3,4,5,6,7,8,9};

    List<Integer> lst = new ArrayList<Integer>();

    int MiniTest[][] = new int[3][3];
    int formattedBoard[][] = new int [9][9];
    
    //Map<BigInteger, int[][]> completedBoards = new HashMap<>();
    Map<Integer, int[][]> completedBoards = new HashMap<>();

    //Need to change this into BigInteger
    //BigInteger numComplete9x9Boards = new BigInteger("1");
    int numComplete9x9Boards=1;   //number completed 9x9 boards....

    StringJoiner sj1 = new StringJoiner(",");

    int [][] nineByNine = new int[][]{
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0}};


    int totalNumbersProcessed=1;
    long permutations;
    String Permutations3x3into9x9;

    int threeBythree[][] = new int[3][3];

    Set<String> s = new HashSet();

    StringJoiner sj;
    int storeMiniGrids[][][];
    int currentSize;
    int newSize;
    int[][] miniGrid;
    int[][][] miniGridContainer;

    List<Integer> copy = new ArrayList<>(lst);

    boolean endFirstRow3x3=false;
    Random rand = new Random();


    //We are now using Set PermutationAllBoards to hold the completed board (currentStringJoinerFullGrid)
    //This can be phased out
    String[] completedBoardsLogs = new String[10000];

    int count=0;
    int rowIndex=0;
    int colIndex=0;

    int randomNumber1to9List;
    boolean failedColumns;
    boolean failedRows;
    boolean sudokuSuccess;

    //Taken from previous code
    int position;
    boolean hasRegisteredInvalidPermutationSequenceRow;
    boolean hasRegisteredInvalidPermutationSequenceColumn;
    int gridNumber;
    int numFullViolation;

    //now made this global, inline with violation code
    int[] storeRetrieved3x3Grid=new int[9];

    //Taken from violation code
    //we know it is resticted to 9 elements per row
    //the number of rows can be gigantic since it create lots violations.
    //I am totally unsure so for now will use large number
    //whole array might need to be changed datatype in future
    int [][]blockedPermutationNumberSequence = new int[2000000][9];

    //taken from violation code
    int uniqueEntries=0;

    //taken from violation code
    boolean hasMatchSecondPermutationNumber=false;

    int pos=0;
    int marker=0;

    int numberOf3x3Processed=0;

    boolean hasExecuteOnce;
    int successfulInputted3x3=0;

    public void wipe9x9Board(int [][]formattedBoard, int nineByNine[][])
    {
        for (int q=0; q<nineByNine.length; q++)
        {
            for (int r=0; r<nineByNine[0].length; r++)

            {
                formattedBoard[q][r]=0;
                nineByNine[q][r]=0;
            }
        }
    }

    public Sudoku(long permutations, String  Permutations3x3into9x9)
    {
        this.permutations =permutations;
        this.Permutations3x3into9x9=Permutations3x3into9x9;

        fill3x3();
    }

    public int convertStringTo3x3(String permutations3x3, int getNum)
    {
        int temp;
        char num;
        String numString;

        num=permutations3x3.charAt(getNum);
        numString= String.valueOf(num);

        temp= Integer.parseInt(numString);

        return temp;
    }

    public void fill3x3()
    {
        int row=0;
        int col=0;
        int numbersProcessed;

        sj = new StringJoiner(",");

        System.out.println("There are : " + permutations + " permutations of arranging  3 x 3 grid" );
        System.out.println("There are : " + Permutations3x3into9x9 + " permutations of arranging  3 x 3 grid into 9 x 9:" + "P(362880,9)" );
        System.out.println("There are : 6,670,903,752,021,072,936,960" + " permutations of completing sudoku (taken from internet)");

        System.out.println("This code will attempt to explore but its impossible to expect much");
        System.out.println("It is used for foundation of experimentation but also it has made serious attempt to complete random process to make a grid");
        System.out.println("I am removing excess code so it is ready future development.");

        do
        {
            IntStream stream = Arrays.stream(possibleNumbers);
            stream.forEach(str -> lst.add(str));

            numbersProcessed=0;

            //System.out.println("*****This is the list size------: " + lst.size());   //list size

            //System.out.println("\n******These are permutations completed:" + s.size());  //set size

            do
            {
                endFirstRow3x3=false;

                randomNumber = rand.nextInt(lst.size());

                randomNumber1to9List=lst.get(randomNumber);
                threeBythree[row][col]= randomNumber1to9List;

                sj.add(Integer.toString(randomNumber1to9List));
                lst.remove(randomNumber);

                if (col%2==0 && col!=0)
                {
                    row++;
                    col=0;
                    endFirstRow3x3 = true;
                }

                if (!endFirstRow3x3)
                {
                    col++;
                }

                numbersProcessed++;

            }while(!lst.isEmpty());

            currentSize=s.size();

            s.add(sj.toString());

            newSize=s.size();
            //System.out.println("This is the new set size: " + newSize + "     Added:   " + sj.toString());

            sj=new StringJoiner(" ");

            if (newSize>currentSize)
            {
                mp.put(newSize,threeBythree);
            }

            row=0;
            col=0;

            //}while (s.size()<362880);    // this is getting  <(NUMBER)  x   (3x3 boards)
        }while (s.size()<362880);    // this is getting  <(NUMBER)  x   (3x3 boards)

        fill9x9(mp);
    }

    public void fill9x9(Map<Integer, int[][]> mp)
    {
        boolean hasViolatedBoard=false;

        //System.out.println("VALUE OF POSITION: " + position);
        int temp[][]=new int[3][3];


        int rowCount=0;
        int colCount=0;
        boolean ReachEndColMiniGrid=false;

        //taken from violating code
        gridNumber=1;

        int offset=0;
        //int i=1;
        numberOf3x3Processed=0;
        int m;
        int entry3x3=0;

        boolean condition1=false;
        boolean condition2=false;
        boolean condition3=false;

        //copied from violation code
        int numberMatches=0;



        //loop structure
        //outer:  performs number of boards
        //inner   for hasviolated
        //inner checks for unique entries <9

        //when we execute code, it hits hasviolated
        //so


        //I have used chatGPT advise here to ensure
        //that it remains in this fill9x9 method..
        //this will ensure that I do not perform recursion
        //while (numComplete9x9Boards.compareTo(numberPossibleBoards) < 0)
        //but it is exactly identical to my version
        //while (numComplete9x9Boards.compareTo(numberPossibleBoards)==-1);
        //and I do not think having pre or post condition matters




        do
        {
            //taken from violation code
            if (!hasExecuteOnce)
            {
                hasExecuteOnce=true;
                for (int i=0; i<position;i++)
                {
                    //System.out.println("----------------CURRENT violating permutation sequences: "
                     //       + Arrays.toString(blockedPermutationNumberSequence[i]));
                }
            }

            hasViolatedBoard=false;

            //I have created this while loop
            //to ensure keeps processing if there is hasViolatedBoard

            //do
            //{
                //System.out.println("START PROCESS AGAIN");
                hasViolatedBoard=false;

                //System.out.println("1This is store of 3 x 3 grids: " + Arrays.toString(storeRetrieved3x3Grid));



                //System.out.println("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ: " + position);
                String[] perm3x3 = s.toArray(new String[s.size()]);
                String[] perm3x3Selection = new String[perm3x3.length];

                String second3x3StringPlacedInGrid;
                //{
                uniqueEntries=0;

                //This was fateful error performing this operation here
                //it is best completing when sudokuComplete
                //infact it is not required at all
                //storeRetrieved3x3Grid=new int[9];

                //****This is an implementation that was haunting me for a long time
                //right from my first implementations. I found that it was always changing the
                //permutation sequence when numberOf3x3Processed was a multiple of 9
                //Hence performed modulus.....
                //We know that numberOf3x3Processed is 0 and default value when the code executes this
                //Beyond this, when it returns back to the top of fill9x9() method, it never reaches this state
                //again, it goes from 9 (previous 3x3 block) to  1 (next 3x3 block)
                //So this will prevent re-entry

                if (numberOf3x3Processed%9!=0  || numberOf3x3Processed==0)
                //This is other alternative to the above, a bit more easier to the eye
                //if(totalNumbersProcessed==1)

                {
                    do   //uniqueEntries<9
                    {
                        //required this adjustment
                        //now gets 0-8
                        randomNumber = 1+ rand.nextInt(perm3x3.length-1);

                        if (randomNumber<minimum)
                        {
                            minimum=randomNumber;
                        }

                        if (randomNumber>maximum)
                        {
                            maximum=randomNumber;
                        }

                        //System.out.println("UNIQUE ENTRIES: " + uniqueEntries);

                        //System.out.println("CURRENT permutation numbers generated: "
                        //+ Arrays.toString(storeRetrieved3x3Grid));

                        if ((perm3x3Selection[randomNumber-1])=="ALREADY SELECTED")
                        {
                            //System.out.println("*********************************GRID ALREADY SELECTED" + "("+randomNumber+") " +"GENERATING ANOTHER");

                            //required this adjustment
                            randomNumber = 1+ rand.nextInt(perm3x3.length-1);

                            if (randomNumber<minimum)
                            {
                                minimum=randomNumber;
                            }

                            if (randomNumber>maximum)
                            {
                                maximum=randomNumber;
                            }
                        }
                        else
                        {
                            //System.out.println("MUST BE HERE ELSE");
                            //System.out.println("AREA TO CHECK FOR VIOLATIONS");

                            //System.out.println("*********************************NEW ENTRY: " + randomNumber);
                            storeRetrieved3x3Grid[uniqueEntries]=randomNumber;
                            uniqueEntries++;

                            //At this point, we need to process and check to see if there is violation from block 2 onwards ONLY
                            //we know that it is here since perm3x3Selection[randomNumber] is unique
                            //we now need to check if is acknowledged bad selection
                            //We know blockedPermutationNumberSequence has to be a 2d array
                            //We know it can be various lengths each array depending on where the block the violation occurred


                            //We know we need to perform examination once minimum two permutations have been selected
                            if (uniqueEntries>1 && position!=0)
                            {
                                if (uniqueEntries==9)
                                {
                                    System.out.println("-----------THESE ARE PERMUTATIONS: " + Arrays.toString(storeRetrieved3x3Grid));
                                }

                                //We go through each uniqueEntries, this is just a counter
                                //it will run from 0-8 and used for indexing
                                /*
                                for (int p=numberMatches; p<uniqueEntries;p++)
                                {
                                    ///here we are interested in going down the rows
                                    //that have been populated only
                                    //this is governed by position
                                    //position NEVER gets reset throughout lifecycle of entire code

                                    for (int h=0; h<position; h++)
                                    {
                                        //this will be used to see if all the entries in blockedPermutationNumberSequence
                                        //matches the generated

                                        //numberMatches=0;

                                        for (int u=numberMatches; u<blockedPermutationNumberSequence[0].length; u++)
                                        {
                                            //System.out.println("IN HERE: " + blockedPermutationNumberSequence[h][u]);

                                            if (storeRetrieved3x3Grid[p]==blockedPermutationNumberSequence[h][u])
                                            {
                                                //we also need something to check if at the same index the match, otherwise irrelevant
                                                //p is index of uniqueEntries that resides in storeRetrieved3x3Grid
                                                //u is the index in blockedPermutationNumberSequence which contains the violating permutation number

                                                if (u==p)
                                                {
                                                    //System.out.println("THIS IS VALUE OF U: " + u);
                                                    //System.out.println("THIS IS VALUE OF P: " + p);

                                                    //System.out.println("prev perm number blocked: "+ blockedPermutationNumberSequence[h][u-1]);

                                                    //We know in this section of code there will be a match
                                                    //I have created two sections.
                                                    //This is straight forward and it ensures that there is a match between
                                                    //storeRetrieved3x3Grid[p]  and blockedPermutationNumberSequence[h][u]

                                                    if (numberMatches==0)
                                                    {
                                                        //System.out.println("MATCH index: " + p + " " + " storeRetrieved3x3Grid[p] " + storeRetrieved3x3Grid[p]);
                                                        //System.out.println("h: " + h + " u: " + u + "  MATCH1 blockedPermutationNumberSequence: " + blockedPermutationNumberSequence[h][u]);
                                                    }
                                                    //once again, we know there is a single match here.... And we are now checking
                                                    //to see if the previous value in
                                                    //blockedPermutationNumberSequence[h][u-1]==storeRetrieved3x3Grid[u-1] are identical
                                                    //We need to take this exact concept up to numberMatches==8
                                                    //We would need to create a boolean for each one and then can only assume full violation
                                                    //This is only technique AVAILABLE CHECKING TWO MATCHES

                                                

                                                    if (numberMatches>0)
                                                    {
                                                        for (int z=numberMatches;z>=0;z--)
                                                        {
                                                            //System.out.println("^^^^^^^^^^^^^^^^^^^^^");
                                                            //System.out.println(blockedPermutationNumberSequence[h][z]);
                                                            //System.out.println(storeRetrieved3x3Grid[z]);

                                                            if(blockedPermutationNumberSequence[h][z]==storeRetrieved3x3Grid[z])
                                                            {
                                                                hasMatchSecondPermutationNumber=true;
                                                            }
                                                            else
                                                            {
                                                                hasMatchSecondPermutationNumber=false;
                                                                break;
                                                            }
                                                        }
                                                    }
                                                    //System.out.println("CURRENT permutation numbers generated: " + Arrays.toString(storeRetrieved3x3Grid));
                                                    numberMatches++;

                                                    //We are finding that due to nature of the nested loops
                                                    //the outer loops continue to run once and the most inner
                                                    //will run to maximum execution
                                                    //so we need to force this so that it can compare at next index on
                                                    //both storeRetrieved3x3Grid and blockedPermutationNumberSequence
                                                    //u++;
                                                    //p++;
                                                }
                                            }

                                            if(numberMatches==uniqueEntries && hasMatchSecondPermutationNumber)
                                            {
                                                //System.out.println(numberMatches);
                                                //System.out.println(uniqueEntries);

                                                System.out.println(Arrays.toString(storeRetrieved3x3Grid) +
                                                        "is in full violation with " +
                                                        Arrays.toString(blockedPermutationNumberSequence[h]));

                                                //System.out.println("At index: " + p + " there is violation: " + " permutation number:" + storeRetrieved3x3Grid[p]);
                                                System.out.println("This permutation selection violates the board: ");

                                                hasViolatedBoard=true;

                                                numFullViolation++;

                                                //I need to max out these variables so it breaks out of entire for loop structure
                                                //and back into d
                                                p=uniqueEntries;
                                                h=position;
                                                u=blockedPermutationNumberSequence[0].length;
                                                uniqueEntries=9;

                                                //We also need to set critical variable back to initial state

                                                //System.exit(0);

                                                //sudokuComplete(failedRows,failedColumns);

                                                //generate3x3Grids();
                                            }
                                            else
                                            {
                                                //System.out.println("NO VIOLATIONS FOUND");
                                                hasMatchSecondPermutationNumber=false;
                                                break;
                                            }
                                        }
                                    }
                                }
                                */
                            }

                            //System.out.println("The current permutation numbers:  " + storeRetrieved3x3Grid[uniqueEntries]);

                            numberMatches=0;

                            //System.out.println(uniqueEntries);

                            //We have had to subttract one to ensure that randomNumber can get all
                            //possible values from perm3x3Selection.
                            //This is required because we added 1 to randomNumber before storing it
                            //into storeRetrieved3x3Grid.
                            //Reason is as per the supporting document
                            perm3x3Selection[randomNumber-1]="ALREADY SELECTED";
                        }
                    }while (uniqueEntries<9);
                }

		pos=0;

                for (int z:storeRetrieved3x3Grid)
                {
                    if (pos==marker)
                    {
                        System.out.println("***************************************************************: " + z);
                        //System.out.println("VALUE OF ENTRY in 3x3:" + entry3x3);
                        temp[0][0]=convertStringTo3x3(perm3x3[z],0);
                        temp[0][1]=convertStringTo3x3(perm3x3[z],2);
                        temp[0][2]=convertStringTo3x3(perm3x3[z],4);
                        temp[1][0]=convertStringTo3x3(perm3x3[z],6);
                        temp[1][1]=convertStringTo3x3(perm3x3[z],8);
                        temp[1][2]=convertStringTo3x3(perm3x3[z],10);
                        temp[2][0]=convertStringTo3x3(perm3x3[z],12);
                        temp[2][1]=convertStringTo3x3(perm3x3[z],14);
                        temp[2][2]=convertStringTo3x3(perm3x3[z],16);
                    }
                    pos++;
                }
                marker++;

                //*********************************************************

                if(!hasViolatedBoard)
                {

                    //System.out.println("This is store of 3 x 3 grids: " + Arrays.toString(storeRetrieved3x3Grid));

                    //we no longer initialise it here again since this is used in methods checkUniqueRows and checkUniqueColumns
                    //part of violation code
                    //storeRetrieved3x3Grid = new int[9];
                    //uniqueEntries=0;

                    perm3x3 = s.toArray(new String[s.size()]);

                    if (totalNumbersProcessed<=81)
                    {
                        if (totalNumbersProcessed<=27 && !condition2 && !condition3)
                        {
                            rowIndex=0;
                            colIndex=0;
                            condition1=true;
                            condition2=true;
                            condition3=true;
                        }

                        if (totalNumbersProcessed<=54 && totalNumbersProcessed>27 && condition1 && condition3)
                        {
                            rowIndex=3;
                            colIndex=0;
                            condition2=true;
                            condition1=false;
                            condition3=false;
                        }

                        if (totalNumbersProcessed<=81 && totalNumbersProcessed>54 && condition2 && !condition1)
                        {
                            rowIndex=6;
                            colIndex=0;
                            condition3=false;
                            condition1=true;
                            condition2=false;
                        }
                        ReachEndColMiniGrid=false;

                        if (numberOf3x3Processed==9)
                        {
                            //inline with violation code
                            switch(gridNumber)
                            {
                                case 1:
                                    rowIndex=0;
                                    break;

                                case 2:
                                    rowIndex=0;
                                    break;

                                case 3:
                                    rowIndex=0;
                                    break;

                                case 4:
                                    rowIndex=3;
                                    break;

                                case 5:
                                    rowIndex=3;
                                    break;

                                case 6:
                                    rowIndex=3;
                                    break;

                                case 7:
                                    rowIndex=6;
                                    break;

                                case 8:
                                    rowIndex=6;
                                    break;

                                case 9:
                                    rowIndex=6;
                                    break;
                            }
                        }

                        numberOf3x3Processed=0;

                        for (int n=0; n<temp.length;n++ )
                        {
                            if (colCount>=2 && rowCount!=2)
                            {
                                rowCount++;
                                colCount=0;
                                rowIndex++;

                                if (offset==0)
                                {
                                    colIndex=0;
                                }
                                else
                                {
                                    colIndex=offset;
                                }

                                if (colIndex==8 && numberOf3x3Processed==9)
                                {
                                    colIndex=0;
                                    rowIndex=rowIndex+3;
                                    ReachEndColMiniGrid=true;
                                }

                                if (colIndex!=8 && numberOf3x3Processed==9)
                                {
                                    colIndex=colIndex+1;
                                    rowIndex=0;
                                }
                            }

                            for (int k=0; k<temp[0].length;k++)
                            {
                                numberOf3x3Processed++;

                                if (k==0)
                                {
                                    offset=colIndex;
                                }

                                /*
                                System.out.println("Selecting grid (3x3) " + gridNumber +" from : "+ storeRetrieved3x3Grid.length);
                                System.out.println("Total numbers processed so far: " + totalNumbersProcessed + " out of 81");
                                System.out.println("Current offset in 9x9 grid: " + offset);
                                System.out.println("Starting in this col in 9 x 9: " + colIndex);
                                System.out.println("The current coordinate(3x3):  " + "(" +rowCount +","+ colCount +")");
                                System.out.println("Following number chosen: " + temp[rowCount][colCount]);
                                System.out.println("being stored at coordinate(9x9): " + "(" + rowIndex + "," + colIndex +")");
                                System.out.println("currently processing this from 3 x 3:" + "(" + rowCount + "," +colCount+")");
                                */

                                sj.add(temp[rowCount][colCount] + "("+rowIndex+","+colIndex+")");

                                nineByNine[rowIndex][colIndex]=temp[rowCount][colCount];

                                realTime9x9Fill(sj.toString());

                                //System.out.println("FILLING BOARD REAL TIME: " + totalNumbersProcessed);
                                //System.out.println("Using entry3x3=" + entry3x3 + " perm=" + perm3x3[entry3x3]);

                                //display9x9();

                                colCount++;
                                colIndex++;

                                if (numberOf3x3Processed==9)
                                {
                                    colCount=0;
                                    rowCount=0;
                                }

                                if (totalNumbersProcessed!=0 && totalNumbersProcessed%9==0)
                                {

                                    //System.out.println("row: " + failedRows);
                                    //System.out.println("col: " + failedColumns);
                                    //System.out.println("Numbers processed in 3x3 grid:" + numberOf3x3Processed);

                                    if (numberOf3x3Processed==9)
                                    {
                                        if (!failedRows&& !failedColumns)
                                        {
                                            successfulInputted3x3++;
                                        }
                                        //else
                                        //{
                                            //successfulInputted3x3=0;
                                        //}
                                    }

                                    //System.out.println("Streak of successful 3x3 blocks: " + successfulInputted3x3);
                                    //inline with violation code
                                    gridNumber++;
                                }

                                if (totalNumbersProcessed%81==0)
                                {
                                    completedBoards.put(numComplete9x9Boards,nineByNine);

                                    //I have now completed this modification to support BigInteger
                                    numAttempts++;
                                    //numAttempts=numAttempts.add(new BigInteger("1"));

                                    //I adjusted the current suduko board with this value:  numSuccessfulCompletedBoard
                                    System.out.println("\n*********************Current completed sudoku board(s): " + numSuccessfulCompletedBoards + "  out of " + Permutations3x3into9x9 + "  Attempts: " + numAttempts);
                                    System.out.println("NUMBER RECORDED PERMUTATION SEQUENCE VIOLATIONS (includes duplicate entries): " + position);
                                    System.out.println("NUMBER BLOCKED SEQUENCES IN EXECUTION: " + numFullViolation);
                                    System.out.println("SUCCESSFUL INPUTTED 3x3 GRIDS ONTO BOARD WITHOUT VIOLATION:  " + successfulInputted3x3);

                                    totalNumbersProcessed=0;
                                    //i=1;
                                    sj = new StringJoiner(" ");

                                    if (sudokuComplete(failedRows, failedColumns))
                                    {
                                        storeRetrieved3x3Grid=new int[9];
                                    }
                                }

                                totalNumbersProcessed++;
                            }
                        }
                        //System.out.println("*************************************");
                    }
                }
                //}
            //}while (hasViolatedBoard);
        } while (numComplete9x9Boards<numberPossibleBoards);

        //This has been removed as per advise from chatGPT and moved to top as while loop
        //}

    }  //end of method

    public void print9x9Board(String currentStringJoinerFullGrid, int numComplete9x9Boards)
    {
        //System.out.println("STORING: " + currentStringJoinerFullGrid);
        permutationAllBoards.add(currentStringJoinerFullGrid);

        numComplete9x9Boards = permutationAllBoards.size();

        System.out.println("********************************************************************************");
        System.out.println("\nThis is your board number " + (numComplete9x9Boards) + " summary: " + currentStringJoinerFullGrid);

        System.out.println("********************************************************************************");
        count=count+1;
    }

    public void realTime9x9Fill(String history)
    {
        int row=0;
        int col=0;
        int boardValue=0;
        int startLastNumber;

        int rowtoInt=0;
        int coltoInt=0;
        int boardValuetoInt=0;

        if (history.lastIndexOf(" ")==-1)
        {
            row = Character.getNumericValue(history.charAt(2));
            col = Character.getNumericValue(history.charAt(4));
            boardValue= Character.getNumericValue(history.charAt(0));

            formattedBoard [row][col]=boardValue;
        }
        else
        {
            startLastNumber=history.lastIndexOf(" ");
            row = history.charAt((startLastNumber+3));
            col = history.charAt((startLastNumber+5));
            boardValue = history.charAt((startLastNumber+1));

            rowtoInt = Character.getNumericValue(row);
            coltoInt = Character.getNumericValue(col);
            boardValuetoInt= Character.getNumericValue(boardValue);

            formattedBoard [rowtoInt][coltoInt]=boardValuetoInt;
        }

        checkUniqueRows(formattedBoard, rowIndex);
        checkUniqueColumns(formattedBoard, colIndex);
    }

    public void display9x9()
    {
        for (int i=0; i<formattedBoard.length; i++)
        {
            sj1= new StringJoiner(" ");

            for (int j=0; j<formattedBoard[0].length; j++)
            {
                sj1.add(Integer.toString(formattedBoard[i][j]));

            }
            System.out.println(sj1);
        }
    }

    public boolean checkUniqueRows(int[][] nineByNine, int rowIndex)
    {
        summary1 = new StringJoiner("| ");
        //System.out.println("**************************************************************************************");

        int occurenceNumberRow=0;

        for (int j=0; j<possibleNumbers.length; j++)
        {
            occurenceNumberRow=0;

            for (int i=0; i<nineByNine[0].length; i++)
            {
                if (possibleNumbers[j]==nineByNine[rowIndex][i])
                {
                    occurenceNumberRow++;

                    if (occurenceNumberRow>1 && !failedRows)
                    {
                        failedRows = true;
                    }
                }
            }

            //We know at this point, we do not not have sufficient information to ascertain which block it has occured on
            //We only have information on the row
            //We know that during fill3x3 method, this level of information is available
            //System.out.println("Selecting grid (3x3) " + gridNumber +" from : "+ s.size());


            //System.out.println("Number: " + possibleNumbers[j] + " has occured: " + occurenceNumberRow +  " times in  row " + rowIndex + " grid number: " + gridNumber);
            summary1.add("N:" + String.valueOf(possibleNumbers[j]) + "  O:" + String.valueOf(occurenceNumberRow) + "  Row:" + String.valueOf(rowIndex));

            //if (gridNumber==3)
            //{
            //  System.exit(0);
            //}

            //We now have to store all the permutation violating number sequence

            //System.out.println("*****************TEST TO SEE VALUE: " + storeRetrieved3x3Grid[0]);

            if (occurenceNumberRow>1 && !hasRegisteredInvalidPermutationSequenceRow && !hasRegisteredInvalidPermutationSequenceColumn)
            {

                //System.out.println("TEST VALUE: " + storeRetrieved3x3Grid[0]);

                for (int n=0; n<gridNumber;n++)
                {
                    blockedPermutationNumberSequence[position][n]=storeRetrieved3x3Grid[n];

                    System.out.println("2Blocked permutation sequence: " + Arrays.toString(blockedPermutationNumberSequence[position]));
                    hasRegisteredInvalidPermutationSequenceRow=true;

                    //not sure of impact here
                    //totalNumbersProcessed=81;

                }
                position++;

                //This is causing stackoverflow
                //sudokuComplete(failedRows,failedColumns);
            }
        }

        return failedRows;   //returns flag value...
    }

    public boolean checkUniqueColumns(int[][] nineByNine, int colIndex)
    {
        summary = new StringJoiner("| ");
        int occurenceNumberCol=0;

        for (int j=0; j<possibleNumbers.length; j++)
        {
            occurenceNumberCol=0;

            for (int i=0; i<nineByNine.length; i++)
            {
                if (possibleNumbers[j]==nineByNine[i][colIndex])
                {
                    occurenceNumberCol++;

                    if (occurenceNumberCol>1 && !failedColumns)
                    {
                        failedColumns = true;
                    }
                }
            }
            //System.out.println("Number: " + possibleNumbers[j] + " has occured: " + occurenceNumberCol +  " times in column " + colIndex + " grid number: " + gridNumber);
            summary.add("N:" + String.valueOf(possibleNumbers[j]) + "  O:" + String.valueOf(occurenceNumberCol) + "  Col:" + String.valueOf(colIndex));

            if (occurenceNumberCol>1 && !hasRegisteredInvalidPermutationSequenceColumn & !hasRegisteredInvalidPermutationSequenceRow)
            {
                //System.out.println("1TEST` VALUE: " + storeRetrieved3x3Grid[0]);

                for (int n=0; n<gridNumber;n++)
                {
                    //***********************************************************
                    //STRICTLY WE CAN NOT USE THESE SINCE THE COLUMN GRID NUMBERS ARE NOT SEQUENTIAL AND WILL BE HANDLED
                    //INCORRECTLY BY fill9x9. ONCE ALL AREAS OF THIS METHOD AND fill9x9() ARE ENHANCED
                    //THIS LOGIC CAN BE INCORPORATED
                    //blockedPermutationNumberSequence[position][n]=storeRetrieved3x3Grid[n];
                    //System.out.println("1Blocked permutation sequence: " + Arrays.toString(blockedPermutationNumberSequence[position]));
                    //hasRegisteredInvalidPermutationSequenceColumn=true;
                    //************************************************************

                    //not sure of how to bypass current board, it will complete to the end
                    //totalNumbersProcessed=81;
                }
                position++;

                //This is causing StackOverflowError
                //sudokuComplete(failedRows,failedColumns);
            }

        }
        return failedColumns;
    }

    public boolean sudokuComplete(boolean duplicateNumbersRow, boolean duplicateNumbersCol)
    {
        //taken from violating code
        hasRegisteredInvalidPermutationSequenceRow=false;
        hasRegisteredInvalidPermutationSequenceColumn=false;
        gridNumber=1;
        uniqueEntries=0;
        successfulInputted3x3=0;

        numberOf3x3Processed=0;
        pos=0;
        marker=0;
        hasExecuteOnce=false;

        //unsure if this has to be set, taken from violation code
        //totalNumbersProcessed=1;

        if (duplicateNumbersRow || duplicateNumbersCol)
        {
            //System.out.println("**************************");
            System.out.println("Better luck next time, failed on board attempt:" + count + "\tPermutations selected: (" + Arrays.toString(storeRetrieved3x3Grid)+")" + "minimum: "+ minimum + " maximum:" + maximum);
            //System.out.println("N=Number, O=Occurrences Col = Column   "  + summary);
            //System.out.println("N=Number, O=Occurrences Row = Row   "  + summary1);


            //I have disabled this since it will give full board summary... It is not imporatnt for a fail and more importantly burden on the screen outputs
            //I have also moved it from where it had totalNumbersProcessed==81...  it is summary
            //print9x9Board(sj.toString(), numComplete9x9Boards);

            //We can optionally turn this on to view the completed board in the expected format
            //display9x9();

            wipe9x9Board(formattedBoard,nineByNine);

            //System.out.println("**************************");

            System.out.println("Moving onto Board Number: " + numComplete9x9Boards);

            failedRows=false;
            //This was the critical failure before when I had the same variable above
            //reset twice. it practically
            failedColumns=false;

            //fill3x3();

            //fill9x9(mp);
            return false;
        }
        else
        {
            System.out.println("**************************");
            System.out.println("\nCongratulations, sudoku complete on board: " + count + " Permutations selected: (" + Arrays.toString(storeRetrieved3x3Grid)+")");
            System.out.println("Complete solution:" + sj.toString());

            //System.out.println("N=Number, O=Occurrences Col = Column   "  + summary);
            //System.out.println("N=Number, O=Occurrences Row = Row   "  + summary1);
            System.out.println("**************************");

            //Instead of exiting, I have continued for more completions
            
            //Display the completed board
            display9x9();

            //System.exit(0);
            wipe9x9Board(formattedBoard,nineByNine);

            System.out.println("Moving onto Board Number: " + numComplete9x9Boards);

            failedRows=false;

            //This was the critical failure before when I had the same variable above
            //reset twice
            failedColumns=false;
            
            //Need to increment a successful board
            //numSuccessfulCompletedBoards=numSuccessfulCompletedBoards.add(new BigInteger("1"));
            numSuccessfulCompletedBoards++;

            //fill3x3();

            //fill9x9(mp);
            System.exit(0);
            return true;


        }
    }
}

public class Permutation
{
    public static void main(String[] args)
    {
        System.out.println("Welcome to Online IDE!! Happy Coding :)");
        int originalNumber=9;
        int n=originalNumber;
        int r =9;
        Map <Integer, Long> m = new HashMap<>();
        System.out.println("***PERMUTATIONS***");
        System.out.println("P(n,r) = n! / (nÃ¢Ë†â€™r)!");
        System.out.println("P(" + n+","+r+") = " + n+"!" + " / " + "("+n+"-"+r+")!");

        String Permutations3x3into9x9="108,883,584,818,776,183,656,945,007,213,012,309,135,068,193,536,000";
        String sudokuSolutions = "6,670,903,752,021,072,936,960";

        Sudoku sud = new Sudoku (Permutations (n,r,originalNumber, m),Permutations3x3into9x9);
    }

    public static long Permutations (int n, int r, int originalNumber, Map factorialResults)
    {
        long result=0;
        int temp;
        int denominator;

        if (originalNumber<r || r<0)
        {
            System.out.println("please enter n Ã¢â€°Â¥ r Ã¢â€°Â¥ 0");
            System.exit(0);
            return 0;
        }

        if (n>=1)
        {
            result = (n* (Permutations (n-1, r,originalNumber, factorialResults)));
            factorialResults.put(n,result);

            if (n==originalNumber)
            {
                denominator = originalNumber-r;

                if (factorialResults.containsKey(denominator))
                {
                    return result / (long)factorialResults.get(denominator); // this is number permutations
                }
            }
            return result;
        }
        return 1;
    }
}